#include <buola/widgets/ctoolbar.h>

#include <buola/gui/cmenu.h>
#include <buola/image/cfont.h>
#include <buola/image/cimage.h>
#include <buola/app/ctimer.h>

#include <buola/widgets/ctooltip.h>
#include <buola/widgets/ctoolbar.h>
#include <buola/widgets/cmenubar.h>
#include <buola/widgets/ctheme.h>

namespace buola { namespace gui {

CToolBar::CToolBar(PMenu pMenu)
    :   mSelected(-1)
    ,   mOpenSubMenu(-1)
    ,   mPressed(false)
    ,   mTipOn(false)
    ,   mTipTimer(new CTimer(chrono::milliseconds(500)))
    ,   mToolTip(nullptr)
{
    mTipTimer->sTimer.Connect(&CToolBar::OnTimer,this);

    mFont=img::CFont::GetStock(L"control");

    get_default_theme()->SetBackground(this);
    get_default_theme()->PrepareToolBar(this);

    if(pMenu)
        SetMenu(pMenu);
    SetPreferredSize({32,32});
}

CToolBar::~CToolBar()
{
    delete mTipTimer;
}

void CToolBar::SetMenu(PMenu pMenu)
{
    mMenu=pMenu;

    mMenu->sChanged.Connect(&CToolBar::OnMenuChanged,this);

    if(Mapped())
    {
        ShapeAll();
        PosAll();
        Refresh();
    }
}

void CToolBar::ShapeAll()
{
    mItemSize.resize(mMenu->size());

    mMaxSize={0,0};

    for(int i=0;i<mMenu->size();i++)
    {
        PMenuItem lItem=mMenu->Get(i);

        if(lItem->IsSeparator())
        {
            mItemSize[i]={10,30};
        }
        else if(lItem->IsWindow())
        {
            mItemSize[i]=CSize_i(lItem->GetWindow()->Size());
            mItemSize[i].x+=10;
        }
        else
        {
            mItemSize[i]={32,24};
        }

        if(mItemSize[i].x>mMaxSize.x) mMaxSize.x=mItemSize[i].x;
        if(mItemSize[i].y>mMaxSize.y) mMaxSize.y=mItemSize[i].y;

        if(GetStyle(TB_VERTICAL))
        {
            int a=mItemSize[i].x;
            mItemSize[i].x=mItemSize[i].y;
            mItemSize[i].y=a;
        }
    }
}

void CToolBar::PosAll()
{
    mItemPos.resize(mMenu->size());

    if(GetStyle(TB_VERTICAL))
    {
        int lY=8;
        for(int i=0;i<mMenu->size();i++)
        {
            if(mMenu->Get(i)->IsHidden()) continue;
            mItemPos[i]=CPoint_d((Size().x-mItemSize[i].x)/2,lY);
            lY+=mItemSize[i].y;

            if(mMenu->Get(i)->IsWindow())
            {
                mItemPos[i].y+=5;
///\todo this urgently
///                if(mMenu->Get(i)->GetWindow()->Parent()!=this)
///                    mMenu->Get(i)->GetWindow()->SetParent(this);
                mMenu->Get(i)->GetWindow()->Move(mItemPos[i]);
            }
        }
    }
    else
    {
        int lX=8;
        for(int i=0;i<mMenu->size();i++)
        {
            mItemPos[i]=CPoint_d(lX,(Size().y-mItemSize[i].y)/2);
            lX+=mItemSize[i].x;

            if(mMenu->Get(i)->IsWindow())
            {
                mItemPos[i].x+=5;

///\todo this urgently
///                if(mMenu->Get(i)->GetWindow()->Parent()!=this)
///                    mMenu->Get(i)->GetWindow()->SetParent(this);
                mMenu->Get(i)->GetWindow()->Move(mItemPos[i]);
            }
        }
    }
}

void CToolBar::SelectItem(int pItem)
{
    mSelected=pItem;

    mMenu->Get(mSelected)->Trigger();
}

void CToolBar::SelectSubMenu(int i)
{
    mSelected=i;

    if(mOpenSubMenu>=0)
    {
        if(mSelected==mOpenSubMenu) return;
        mSubMenu->Unmap();
    }

    PMenuItem lItem=mMenu->Get(i);

    mSubMenu=new CMenuBar;

    mSubMenu->eClosed.Connect(&CToolBar::OnMenuClosed,this);

///\todo this now!    
///    mSubMenu->CreatePopup(this,lItem->GetSubMenu(),
///            TranslateCoords(CPoint_d(mItemPos[mSelected].x-2,Size().y-2)));

    mSubMenu->Show();

    mOpenSubMenu=mSelected;
}

void CToolBar::ChangeSelection(int pSelected)
{
    int lSelected=mSelected;
    mSelected=pSelected;

    if(mSelected>=mMenu->size()||mSelected<-1) mSelected=-1;

    if(lSelected!=mSelected)
    {
        if(mTipOn) mToolTip->Hide();
        mTipTimer->Enable();

        if(mSelected>=0)
        {
            mTipTimer->Enable();
        }
        else
        {
            mTipTimer->Disable();
        }
        Refresh();
    }
}

///////////////// events //////////////////

void CToolBar::OnExpose(const CExposeEvent &pE)
{
    img::CGC *lGC=pE.mGC;

    get_default_theme()->DrawToolBar(lGC,this,CTheme::DRAW_NONE);

    if(!mMenu->size()) return;

    PMenuItem lThis,lNext,lPrev;

    for(int i=0;i<mMenu->size();i++)
    {
        lThis=mMenu->Get(i);
        if(lThis->IsHidden()) continue;

        lNext=nullptr;
        for(int j=i+1;j<mMenu->size();j++)
        {
            if(!mMenu->Get(j)->IsHidden())
            {
                lNext=mMenu->Get(j);
                break;
            }
        }

        CTheme::EDrawStyle lFlags=CTheme::DRAW_NONE;
        if(i==mSelected)
            lFlags|=CTheme::DRAW_HOVER;
        if(!lPrev||lPrev->IsSeparator()||lPrev->IsWindow())
            lFlags|=CTheme::DRAW_LEFT;
        if(!lNext||lNext->IsSeparator()||lNext->IsWindow())
            lFlags|=CTheme::DRAW_RIGHT;

        get_default_theme()->DrawToolBarItem(lGC,CRect_d(mItemPos[i],mItemSize[i]),
                                    this,lThis,lFlags);
        lPrev=lThis;
    }
}

void CToolBar::OnButtonDown(const CMouseEvent &pE)
{
    if(pE.mButton==EMouseButton::LEFT)
    {
        if(mTipOn)
        {
            mToolTip->Hide();
            mTipOn=false;
        }
        mTipTimer->Disable();
        mPressed=true;

        if(mSelected>=0)
        {
            Refresh();
        }
    }
}

void CToolBar::OnButtonUp(const CMouseEvent &pE)
{
    if(pE.mButton!=EMouseButton::LEFT) return;

    if(mTipOn)
    {
        mToolTip->Hide();
        mTipOn=false;
    }
    mTipTimer->Disable();

    if(mSelected<0)
    {
        mPressed=false;
        return;
    }

    if(mMenu->Get(mSelected)->IsNormalItem())
    {
        mPressed=false;
        Refresh();

        SelectItem(mSelected);
    }
    else if(mMenu->Get(mSelected)->IsSubMenu())
    {
        mPressed=false;
        SelectSubMenu(mSelected);
    }
}

void CToolBar::OnMouseMove(const CMouseEvent &pE)
{
    int lSelected=-1;

    for(int i=0;i<mMenu->size();i++)
    {
        PMenuItem lI=mMenu->Get(i);
        if(lI->IsHidden()) continue;
        if(lI->IsDisabled()) continue;
        if(pE.mPoint.x>=mItemPos[i].x&&
           pE.mPoint.x<mItemPos[i].x+mItemSize[i].x&&
           pE.mPoint.y>=mItemPos[i].y&&
           pE.mPoint.y<mItemPos[i].y+mItemSize[i].y)
        {
            if(!lI->IsWindow()&&!lI->IsSeparator())
                lSelected=i;
            break;
        }
    }
    if(!mTipOn&&mSelected>=0)
        mTipTimer->Enable();

    ChangeSelection(lSelected);
}

void CToolBar::OnMouseOut(const CMouseEvent &pE)
{
    ChangeSelection(mOpenSubMenu);

    if(mTipOn)
    {
        mToolTip->Unmap();
        mTipOn=false;
    }

    mTipTimer->Disable();
}

void CToolBar::OnMenuClosed()
{
    mOpenSubMenu=-1;
    ChangeSelection(-1);
}

void CToolBar::OnMenuChanged()
{
    ShapeAll();
    PosAll();
    Refresh();
}

void CToolBar::OnTimer()
{
    PMenuItem lItem=mMenu->Get(mSelected);
    std::wstring lText=lItem->GetText();
    if(lItem->GetAccelText().length())
    {
        lText+=L" (";
        lText+=lItem->GetAccelText();
        lText+=L")";
    }

    if(!mToolTip)
    {
        mToolTip=new CToolTip(lText);
    }
    else
    {
        mToolTip->RePos();
        mToolTip->SetCaption(lText);
    }

    mToolTip->Map();

    mTipOn=true;
    mTipTimer->Disable();
}

void CToolBar::OnStyleChanged(TStyle pOld)
{
    int lChange=pOld^GetStyle();

    if(lChange&TB_VERTICAL)
    {
    }
}

void CToolBar::OnSize(const CGeometryEvent &pE)
{
    ShapeAll();
    PosAll();
}

/*namespace gui*/ } /*namespace buola*/ }
